;*
;* sha256.inc
;* https://gitlab.com/bztsrc/sha256asm
;*
;* Copyright (C) 2018 bzt (bztsrc@gitlab)
;*
;* Permission is hereby granted, free of charge, to any person
;* obtaining a copy of this software and associated documentation
;* files (the "Software"), to deal in the Software without
;* restriction, including without limitation the rights to use, copy,
;* modify, merge, publish, distribute, sublicense, and/or sell copies
;* of the Software, and to permit persons to whom the Software is
;* furnished to do so, subject to the following conditions:
;*
;* The above copyright notice and this permission notice shall be
;* included in all copies or substantial portions of the Software.
;*
;* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
;* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
;* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
;* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
;* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
;* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
;* DEALINGS IN THE SOFTWARE.
;*
;* @brief Very small SHA-256 implementation for protected mode

;*** interface macros ***

;**
;* Initialize the SHA256_CTX
;* void sha256_init(void)
;*
;%macro sha256_init 0
;{
;            call sha_init
;}

sha256_init:
    call sha_init
    ret

;**
;* Add a buffer to SHA256_CTX
;* void sha256_update(unsigned char *buffer, size_t len)
;*
;%macro sha256_update 2 ; buf, len
;{
;if ~ buf eq esi
;            mov         esi, buf   <----------------
;end if
;if ~ len eq ecx
;            mov         ecx, len
;end if
;            call        sha_upd
;}

sha256_update:
;    mov         esi, buf
    call        sha_upd
    ret

;**
;* Return the SHA-256 checksum
;* void sha256_final(unsigned char *chk[32])
;*
;%macro sha256_final 1 ; buf
;{
;if ~ buf eq edi
;            mov         edi, buf
;end if
;            call        sha_final
;}

sha256_final:
;    mov         edi, buf
    call        sha_final
    ret

;*** implementation, text segment ***

            ; No input. Clobbers EAX
sha_init:   xor         eax, eax
            mov         dword [sha_l], eax
            mov         dword [sha_b], eax
            mov         dword [sha_b+4], eax
            mov         dword [sha_s   ], 06a09e667h
            mov         dword [sha_s+ 4], 0bb67ae85h
            mov         dword [sha_s+ 8], 03c6ef372h
            mov         dword [sha_s+12], 0a54ff53ah
            mov         dword [sha_s+16], 0510e527fh
            mov         dword [sha_s+20], 09b05688ch
            mov         dword [sha_s+24], 01f83d9abh
            mov         dword [sha_s+28], 05be0cd19h
            ret

            ; IN: ESI = buffer, ECX = length. Clobbers EAX, EDI.
sha_upd:    mov         edi, dword [sha_l]
            add         edi, sha_d
            ; if(len>0)
            or          ecx, ecx
            jz          .end
            ; for(;len--;d++) {
            ; ctx->d[ctx->l++]=*d;
.next:      movsb
            inc         byte [sha_l]
            ; if(ctx->l==64) {
            cmp         byte [sha_l], 64
            jne         .f
            ; sha256_t(ctx);
            call        sha_final.sha_t
            ; SHA_ADD(ctx->b[0],ctx->b[1],512);
            add         dword [sha_b], 512
            adc         dword [sha_b+4], 0
            ; ctx->l=0;
            mov         byte [sha_l], 0
            ; edi=sha_d
            sub         edi, 64
            ; }
.f:         dec         ecx
            jnz         .next
.end:       ret

            ; IN: EDI = output buffer. Clobbers EAX, EBX, ECX.
sha_final:  push        esi
            push        edi
            mov         ebx, edi
            ; i=ctx->l; ctx->d[i++]=0x80;
            mov         edi, dword [sha_l]
            mov         ecx, edi
            add         edi, sha_d
            mov         al, 80h
            stosb
            inc         ecx
            xor         eax, eax
            ; if(ctx->l<56) {while(i<56) ctx->d[i++]=0x00;}
            cmp         cl, 57
            jae         .f
            neg         ecx
            add         ecx, 56
            repnz       stosb
            jmp         .padded
.f:         ; else {while(i<64) ctx->d[i++]=0x00;sha256_t(ctx);memset(ctx->d,0,56);}
            neg         ecx
            add         ecx, 64
            repnz       stosb
            call        .sha_t
            mov         ecx, 56/4
            mov         edi, sha_d
            repnz       stosd
.padded:    ; SHA_ADD(ctx->b[0],ctx->b[1],ctx->l*8);
            mov         eax, dword [sha_l]
            shl         eax, 3
            add         dword [sha_b], eax
            adc         dword [sha_b+4], 0
            ; ctx->d[63]=ctx->b[0];ctx->d[62]=ctx->b[0]>>8;ctx->d[61]=ctx->b[0]>>16;ctx->d[60]=ctx->b[0]>>24;
            mov         eax, dword [sha_b]
            bswap       eax
            mov         dword [sha_d+60], eax
            ; ctx->d[59]=ctx->b[1];ctx->d[58]=ctx->b[1]>>8;ctx->d[57]=ctx->b[1]>>16;ctx->d[56]=ctx->b[1]>>24;
            mov         eax, dword [sha_b+4]
            bswap       eax
            mov         dword [sha_d+56], eax
            ; sha256_t(ctx);
            call        .sha_t
            ; for(i=0;i<4;i++) {
            ;   h[i]   =(ctx->s[0]>>(24-i*8)); h[i+4] =(ctx->s[1]>>(24-i*8));
            ;   h[i+8] =(ctx->s[2]>>(24-i*8)); h[i+12]=(ctx->s[3]>>(24-i*8));
            ;   h[i+16]=(ctx->s[4]>>(24-i*8)); h[i+20]=(ctx->s[5]>>(24-i*8));
            ;   h[i+24]=(ctx->s[6]>>(24-i*8)); h[i+28]=(ctx->s[7]>>(24-i*8));
            ; }
            mov         edi, ebx
            mov         esi, sha_s
            mov         cl, 8
.back:      lodsd
            bswap       eax
            stosd
            dec         cl
            jnz         .back
            pop         edi
            pop         esi
            ret
; private func, sha transform
.sha_t:     push        esi
            push        edi
            push        edx
            push        ecx
            push        ebx
            ; for(i=0,j=0;i<16;i++,j+=4) m[i]=(ctx->d[j]<<24)|(ctx->d[j+1]<<16)|(ctx->d[j+2]<<8)|(ctx->d[j+3]);
            mov         cl, 16
            mov         edi, _m
            mov         esi, sha_d
.back1:     lodsd
            bswap       eax
            stosd
            dec         cl
            jnz         .back1
            ; for(;i<64;i++) m[i]=SHA_SIG1(m[i-2])+m[i-7]+SHA_SIG0(m[i-15])+m[i-16];
            mov         cl, 48
            ;   SHA_SIG0[m[i-15])       (SHA_ROTR(x,7)^SHA_ROTR(x,18)^((x)>>3))
.back2:     mov         eax, dword [edi-15*4]
            mov         ebx, eax
            mov         edx, eax
            ror         eax, 7
            ror         ebx, 18
            shr         edx, 3
            xor         eax, ebx
            xor         eax, edx
            ;   SHA_SIG1(m[i-2])        (SHA_ROTR(x,17)^SHA_ROTR(x,19)^((x)>>10))
            mov         ebx, dword [edi-2*4]
            mov         edx, ebx
            ror         ebx, 17
            ror         edx, 19
            xor         ebx, edx
            rol         edx, 19
            shr         edx, 10
            xor         ebx, edx
            add         eax, ebx
            ;   m[i-7]
            add         eax, dword [edi-7*4]
            ;   m[i-16]
            add         eax, dword [edi-16*4]
            stosd
            dec         cl
            jnz         .back2
            ; a=ctx->s[0];b=ctx->s[1];c=ctx->s[2];d=ctx->s[3];
            ; e=ctx->s[4];f=ctx->s[5];g=ctx->s[6];h=ctx->s[7];
            xor         ecx, ecx
            mov         cl, 8
            mov         esi, sha_s
            mov         edi, _a
            repnz       movsd
            ; for(i=0;i<64;i++) {
            mov         esi, _m
.back3:     ; t1=h+SHA_EP1(e)+SHA_CH(e,f,g)+sha256_k[i]+m[i];
            mov         eax, dword [_h]
            mov         dword [t1], eax
            ;   SHA_EP1(e)              (SHA_ROTR(x,6)^SHA_ROTR(x,11)^SHA_ROTR(x,25))
            mov         eax, dword [_e]
            mov         ebx, eax
            ror         eax, 6
            ror         ebx, 11
            xor         eax, ebx
            ror         ebx, 14 ; 25 = 11+14
            xor         eax, ebx
            add         dword [t1], eax
            ;   SHA_CH(e,f,g)           (((x)&(y))^(~(x)&(z)))
            mov         eax, dword [_e]
            mov         ebx, eax
            not         ebx
            and         eax, dword [_f]
            and         ebx, dword [_g]
            xor         eax, ebx
            add         dword [t1], eax
            ;   sha256_k[i]
            mov         eax, dword [sha256_k+4*ecx]
            add         dword [t1], eax
            ;   m[i]
            lodsd
            add         dword [t1], eax
            ; t2=SHA_EP0(a)+SHA_MAJ(a,b,c);
            ;   SHA_EP0(a)              (SHA_ROTR(x,2)^SHA_ROTR(x,13)^SHA_ROTR(x,22))
            mov         eax, dword [_a]
            mov         ebx, eax
            ror         eax, 2
            ror         ebx, 13
            xor         eax, ebx
            ror         ebx, 9 ; 22 = 13+9
            xor         eax, ebx
            mov         dword [t2], eax
            ;   SHA_MAJ(a,b,c)          (((x)&(y))^((x)&(z))^((y)&(z)))
            mov         eax, dword [_a]
            mov         edx, dword [_c]
            mov         ebx, eax
            and         eax, dword [_b]
            and         ebx, edx
            xor         eax, ebx
            mov         ebx, dword [_b]
            and         ebx, edx
            xor         eax, ebx
            add         dword [t2], eax
            ; h=g;g=f;f=e;e=d+t1;d=c;c=b;b=a;a=t1+t2;
            mov         eax, dword [_g]
            mov         dword [_h], eax
            mov         eax, dword [_f]
            mov         dword [_g], eax
            mov         eax, dword [_e]
            mov         dword [_f], eax
            mov         eax, dword [_d]
            add         eax, dword [t1]
            mov         dword [_e], eax
            mov         eax, dword [_c]
            mov         dword [_d], eax
            mov         eax, dword [_b]
            mov         dword [_c], eax
            mov         eax, dword [_a]
            mov         dword [_b], eax
            mov         eax, dword [t1]
            add         eax, dword [t2]
            mov         dword [_a], eax
            ; }
            inc         cl
            cmp         cl, 64
            jne         .back3
            ; ctx->s[0]+=a;ctx->s[1]+=b;ctx->s[2]+=c;ctx->s[3]+=d;
            ; ctx->s[4]+=e;ctx->s[5]+=f;ctx->s[6]+=g;ctx->s[7]+=h;
            mov         cl, 8
            mov         esi, _a
            mov         edi, sha_s
.back4:     lodsd
            add         dword [edi], eax
            add         edi, 4
            dec         cl
            jnz         .back4
            pop         ebx
            pop         ecx
            pop         edx
            pop         edi
            pop         esi
            xor         eax, eax
            ret
sha256_k:   dd          0428a2f98h, 071374491h, 0b5c0fbcfh, 0e9b5dba5h, 03956c25bh, 059f111f1h, 0923f82a4h, 0ab1c5ed5h
            dd          0d807aa98h, 012835b01h, 0243185beh, 0550c7dc3h, 072be5d74h, 080deb1feh, 09bdc06a7h, 0c19bf174h
            dd          0e49b69c1h, 0efbe4786h, 00fc19dc6h, 0240ca1cch, 02de92c6fh, 04a7484aah, 05cb0a9dch, 076f988dah
            dd          0983e5152h, 0a831c66dh, 0b00327c8h, 0bf597fc7h, 0c6e00bf3h, 0d5a79147h, 006ca6351h, 014292967h
            dd          027b70a85h, 02e1b2138h, 04d2c6dfch, 053380d13h, 0650a7354h, 0766a0abbh, 081c2c92eh, 092722c85h
            dd          0a2bfe8a1h, 0a81a664bh, 0c24b8b70h, 0c76c51a3h, 0d192e819h, 0d6990624h, 0f40e3585h, 0106aa070h
            dd          019a4c116h, 01e376c08h, 02748774ch, 034b0bcb5h, 0391c0cb3h, 04ed8aa4ah, 05b9cca4fh, 0682e6ff3h
            dd          0748f82eeh, 078a5636fh, 084c87814h, 08cc70208h, 090befffah, 0a4506cebh, 0bef9a3f7h, 0c67178f2h

; SHA256_CTX and temporary variables in bss segment
sha_d:      times 64 db 0       ; db         64 dup ?  
sha_l:      dd          0
sha_b:      times 2 dd  0       ; dd          2 dup ?
sha_s:      times 8 dd  0       ; dd          8 dup ?
_a:         dd          0
_b:         dd          0
_c:         dd          0
_d:         dd          0
_e:         dd          0
_f:         dd          0
_g:         dd          0
_h:         dd          0
t1:         dd          0
t2:         dd          0
_m:         times 64 dd 0       ; dd          64 dup ?

